算法与数据结构--图的实现、基本操作及应用

#include<iostream>
#include<queue>
#include<stack>
using namespace std;

#define INFINITY DBL_MAX     //无穷大
#define MAX_VERTEX_NUM 20 //最大顶点个数
enum GraphKind //图的类型
{
	DG,DN,UDG,UDN//有向图、有向网、无向图、无向网
};

//弧结构
typedef struct ArcCell
{
	double adj;//权值,无权图用1表示
}AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];
//邻接矩阵图结构
 struct MGraph
{
	int vexs[MAX_VERTEX_NUM];//顶点集合
	AdjMatrix arecs;//邻接矩阵
	int vexnum,arcnum;//顶点数、弧数
	GraphKind kind;//图的类型
};


//表节点
 struct ArcNode
 {
	int adjvex;//弧的顶点位置
	ArcNode * nextarc;
	double adj;//弧的权值
 };
//头节点
 typedef struct VNode
 {
	int data;//顶点序号信息
	ArcNode * firstarc;
 }AdjList[MAX_VERTEX_NUM];
 //邻接表
 struct ALGraph
 {
	 int vexs[MAX_VERTEX_NUM];//顶点集合
	 AdjList vertices; //邻接链表
	 int vexnum,arcnum;//顶点数、弧数
	 int kind;//图的类型
 };

//显示主菜单
void ShowMainMenu()
{
	cout<<"\n";
	cout<<"  ***************图的基本操作及应用******************\n";
	cout<<"  *  1 无向图的基本操作及应用                      *\n";
	cout<<"  *  2 有向图的基本操作及应用                      *\n";
    cout<<"  *  3 无向网的基本操作及应用                      *\n";
	cout<<"  *  4 有向网的基本操作及应用                      *\n";
	cout<<"  *  5 退出                                        *\n";
	cout<<"  ***************************************************\n";
}
/*
*无向图的函数集
*/
//创建无向图的邻接矩阵
bool CreatUDG_M(MGraph & MG)
{
	MG.kind = UDG;
	cout<<"请输入该无向图的顶点个数、弧的条数:"<<endl;
	cin>>MG.vexnum>>MG.arcnum;
	//初始化顶点集合
	cout<<"依次输入顶点序号"<<endl;
	for(int i = 0;i<MG.vexnum;i++)  cin>>MG.vexs[i];
	//初始化邻接矩阵
	for(int i = 0;i<MG.vexnum;i++)
	{
		for(int j = 0;j<MG.vexnum;j++)
		 {
			 MG.arecs[i][j].adj = INFINITY;
		 }
	}
	//构造邻接矩阵
	for(int i = 0;i<MG.arcnum;i++)
	{
		int v1,v2;
		cout<<"依次输入弧的两个顶点序号:"<<endl;
		cin>>v1>>v2;
		int *p1 = find(MG.vexs,MG.vexs+MG.vexnum,v1);
		int *p2 = find(MG.vexs,MG.vexs+MG.vexnum,v2);
		if(p1==MG.vexs+MG.vexnum||p2==MG.vexs+MG.vexnum) return false;
		MG.arecs[(p1-MG.vexs)][(p2-MG.vexs)].adj = 1;
		//无向图的邻接矩阵是对称矩阵
		MG.arecs[(p2-MG.vexs)][(p1-MG.vexs)].adj = 1;
	}
	//输出该邻接矩阵
	cout<<"该邻接矩阵为(-1代表无穷大):"<<endl;
	for(int i = 0;i<MG.vexnum;i++)
	{
		for(int j = 0;j<MG.vexnum;j++)
	  {
		  if(MG.arecs[i][j].adj==INFINITY) cout<<"∞  ";
		  else
		  {
			  cout<<MG.arecs[i][j].adj<<"  ";
		  }
	  }
		cout<<endl;
	}
	return true;
}
//创建无向图的邻接表
bool CreatUDG_ALG(ALGraph & ALG)
{
	ALG.kind =  UDG;
	cout<<"请输入该无向图的顶点个数、弧的条数:"<<endl;
	cin>>ALG.vexnum>>ALG.arcnum;
	//初始化顶点集合
	cout<<"依次输入顶点序号"<<endl;
	for(int i = 0;i<ALG.vexnum;i++)  cin>>ALG.vexs[i];
	//构造邻接表
	for(int i  = 0;i<ALG.vexnum;i++)
	{
	 //初始化头结点的data信息
		ALG.vertices[i].data = ALG.vexs[i];
		ALG.vertices[i].firstarc = 0;
	 //循环输入该头结点的邻接弧
		cout<<"输入与序号为"<<ALG.vexs[i]<<"节点相邻的节点序号"<<endl;
		int v1;
		ArcNode * rp = ALG.vertices[i].firstarc;
		while (cin>>v1)
		{
			
			int *p1 =  find(ALG.vexs,ALG.vexs+ALG.vexnum,v1);
			if(p1==ALG.vexs+ALG.vexnum)return false;
			ArcNode *pA = (ArcNode *)malloc(sizeof(ArcNode));
			if(!pA) return false;
			pA->adj = 1;
			pA->adjvex = p1-ALG.vexs;
			pA->nextarc = 0;
			if(0==ALG.vertices[i].firstarc) {ALG.vertices[i].firstarc = pA; rp = pA;}
			else{rp->nextarc = pA; rp = pA;}
		}
		cin.clear();//清空输入流
	}
	//输出邻接表
	for(int i  = 0;i<ALG.vexnum;i++)
	{
		cout<<"'"<<ALG.vexs[i]<<"'";
		for(ArcNode * rp = ALG.vertices[i].firstarc;rp!=0;rp = rp->nextarc)
	  {
		  cout<<"--->"<<(*rp).adjvex;
	  }
		cout<<endl;
	}
	return true;
}
//无向图的深度优先遍历
void Visit_fun(int & t)
{
	t++;
}
void UDG_DFS(ALGraph &ALG,int v,bool visited[],void(*visit)(int& t))
{
	visited[v] = true;visit(ALG.vexs[v]);
	for(ArcNode * rp = ALG.vertices[v].firstarc;rp!=0;rp = rp->nextarc)
	{
		if(!visited[(*rp).adjvex]) UDG_DFS(ALG,(*rp).adjvex,visited,visit);
	}
}
void UDG_DFSTraverse(ALGraph &ALG,void(*visit)(int &t))
{
	bool *visited = new bool[ALG.vexnum];
	for(int i = 0;i<ALG.vexnum;i++) visited[i] =  false;
	for(int i = 0;i<ALG.vexnum;i++)
	{
		if(!visited[i]) UDG_DFS(ALG,i,visited,visit);
	}

	//測试数据序号是否都被改动
	cout<<"測试结果(遍历每一个节点,并将节点的序号加一):"<<endl;
	for(int i = 0;i<ALG.vexnum;i++)
	{
		cout<<ALG.vexs[i]<<"  "<<endl;
	}
}
//无向图的广度优先遍历
void UDG_BFSTraverse(ALGraph &ALG,void(*visit)(int &t))
{
	//辅助訪问数组
	bool *visited = new bool[ALG.vexnum];
	for(int i = 0;i<ALG.vexnum;i++) visited[i] =  false;
	//辅助队列
	queue<int> Queue;
	for(int i= 0;i<ALG.vexnum;i++)
	{
		if(!visited[i])
		{ visited[i] = true;
		  //先訪问再如队列
		  visit(ALG.vexs[i]);
		  Queue.push(i);
		  while (!Queue.empty())
		  {
			  int v = Queue.front();//出队
			  Queue.pop();
			  for(ArcNode * rp = ALG.vertices[v].firstarc;rp!=0;rp = rp->nextarc)
			  {
			    if(!visited[(*rp).adjvex]) 
				{
					visited[(*rp).adjvex] = true;
					visit(ALG.vexs[(*rp).adjvex]);
					Queue.push((*rp).adjvex);
				}
			  }
		  }
		
		}
	}
	//測试数据序号是否都被改动
	cout<<"測试结果(遍历每一个节点,并将节点的序号加一):"<<endl;
	for(int i = 0;i<ALG.vexnum;i++)
	{
		cout<<ALG.vexs[i]<<"  "<<endl;
	}
}
//无向图操作菜单
void UndirectedGraph()
{
	MGraph MG;
	ALGraph ALG;
	int n;
	do
	{
		cout<<"\n";
		cout<<"  ***************无向图的基本操作及应用***************\n";
	    cout<<"  *  1 创建无向图的邻接矩阵                         *\n";
		cout<<"  *  2 创建无向图的邻接表                           *\n";
	    cout<<"  *  3 无向图的深度优先遍历                         *\n";
	    cout<<"  *  4 无向图的广度优先遍历                         *\n";
		cout<<"  *  5 退出                                         *\n";
	    cout<<"  ****************************************************\n";
		cin>>n;
		switch(n){
			case 1:
				CreatUDG_M(MG);
				break;
			case 2:
				CreatUDG_ALG(ALG);
				break;
			case 3:
				UDG_DFSTraverse(ALG,Visit_fun);
				break;
			case 4:
				UDG_BFSTraverse(ALG,Visit_fun);
				break;
			default:
				if (n!=5)
					cout<<"错误。又一次输入\n";
		}
	}while(n!=5);
}


/*
*有向图的函数集
*/
//创建有向图的邻接矩阵
bool CreatDG_M(MGraph& MDG)
{
	MDG.kind = DG;
	cout<<"请输入该有向图的顶点个数、弧的条数:"<<endl;
	cin>>MDG.vexnum>>MDG.arcnum;
	//初始化顶点集合
	cout<<"依次输入顶点序号"<<endl;
	for(int i = 0;i<MDG.vexnum;i++)  cin>>MDG.vexs[i];
	//初始化邻接矩阵
	for(int i = 0;i<MDG.vexnum;i++)
	{
		for(int j = 0;j<MDG.vexnum;j++)
		 {
			 MDG.arecs[i][j].adj = INFINITY;
		 }
	}
	//构造邻接矩阵
	for(int i = 0;i<MDG.arcnum;i++)
	{
		int v1,v2;
		cout<<"依次输入弧的弧尾序号、弧头序号:"<<endl;
		cin>>v1>>v2;
		int *p1 = find(MDG.vexs,MDG.vexs+MDG.vexnum,v1);
		int *p2 = find(MDG.vexs,MDG.vexs+MDG.vexnum,v2);
		if(p1==MDG.vexs+MDG.vexnum||p2==MDG.vexs+MDG.vexnum) return false;
		MDG.arecs[(p1-MDG.vexs)][(p2-MDG.vexs)].adj = 1;
	}
	//输出该邻接矩阵
	cout<<"该邻接矩阵为:"<<endl;
	for(int i = 0;i<MDG.vexnum;i++)
	{
		for(int j = 0;j<MDG.vexnum;j++)
	  {
		  if(MDG.arecs[i][j].adj==INFINITY) cout<<"∞  ";
		  else
		  {
			  cout<<MDG.arecs[i][j].adj<<"  ";
		  }
	  }
		cout<<endl;
	}
	return true;
}
//创建有向图的邻接表
bool CreatDG_ALG(ALGraph & ALDG)
{
	ALDG.kind =  DG;
	cout<<"请输入该有向图的顶点个数、弧的条数:"<<endl;
	cin>>ALDG.vexnum>>ALDG.arcnum;
	//初始化顶点集合
	cout<<"依次输入顶点序号"<<endl;
	for(int i = 0;i<ALDG.vexnum;i++)  cin>>ALDG.vexs[i];
	//构造邻接表
	for(int i  = 0;i<ALDG.vexnum;i++)
	{
	 //初始化头结点的data信息
		ALDG.vertices[i].data = ALDG.vexs[i];
		ALDG.vertices[i].firstarc = 0;
	 //循环输入该头结点的邻接弧
		cout<<"输入以序号为"<<ALDG.vexs[i]<<"节点为弧尾的弧头节点序号"<<endl;
		int v1;
		ArcNode * rp = ALDG.vertices[i].firstarc;
		while (cin>>v1)
		{
			int *p1 =  find(ALDG.vexs,ALDG.vexs+ALDG.vexnum,v1);
			if(p1==ALDG.vexs+ALDG.vexnum)return false;
			ArcNode *pA = (ArcNode *)malloc(sizeof(ArcNode));
			if(!pA) return false;
			pA->adj = 1;
			pA->adjvex = p1-ALDG.vexs;
			pA->nextarc = 0;
			if(0==ALDG.vertices[i].firstarc) {ALDG.vertices[i].firstarc = pA; rp = pA;}
			else{rp->nextarc = pA; rp = pA;}
		}
		cin.clear();//清空输入流
	}
	//输出邻接表
	for(int i  = 0;i<ALDG.vexnum;i++)
	{
		cout<<"'"<<ALDG.vexs[i]<<"'";
		for(ArcNode * rp = ALDG.vertices[i].firstarc;rp!=0;rp = rp->nextarc)
		{
			  cout<<"--->"<<(*rp).adjvex;
		}
		cout<<endl;
	}
	return true;
}
//拓扑排序
bool TopologicalSort(ALGraph & ALDG)
{
	//入度数组
	int *indegree = new int[ALDG.vexnum];
	//初始化入度数组
	for(int i = 0;i<ALDG.vexnum;i++)
	{
	  int re= 0;
	  for(int j = 0;j<ALDG.vexnum;j++)
	  {
			if(j!=i)//查找入度
			{
				for(ArcNode * rp = ALDG.vertices[j].firstarc;rp!=0;rp = rp->nextarc)
				{
				   if((*rp).adjvex==i) re++;
				}
			}
	  }
	  indegree[i] = re;
	}
	//保存入度为0的栈
	stack<int> Stack;
	for(int i = 0;i<ALDG.vexnum;i++)
	{
		if(0==indegree[i]) Stack.push(i);
	}
	int count = 0;//记录输出节点的个数
	while (!Stack.empty())
	{
		int v = Stack.top();//出栈
		Stack.pop(); count++;
		//输出
		cout<<ALDG.vexs[v]<<"  ";
		for(ArcNode * rp = ALDG.vertices[v].firstarc;rp!=0;rp = rp->nextarc)
		{
			--indegree[(*rp).adjvex];
			if(0==indegree[(*rp).adjvex]) Stack.push((*rp).adjvex);
		}
	}
	if(count<ALDG.vexnum)
	{
		return false;
	}
	return true;
}
//有向图操作菜单
void DirectedGraph ()
{
	MGraph MDG;//有向图邻接矩阵
	ALGraph ALDG;//有向图邻接表
	int n;
	do
	{
		cout<<"\n";
		cout<<"  ***************有向图的基本操作及应用***************\n";
	    cout<<"  *  1 创建有向图的邻接矩阵                         *\n";
		cout<<"  *  2 创建有向图的邻接表                           *\n";
	    cout<<"  *  3 拓扑排序                                     *\n";
		cout<<"  *  4 退出                                         *\n";
	    cout<<"  ****************************************************\n";
		cin>>n;
		switch(n){
			case 1:
				CreatDG_M(MDG);
				break;
			case 2:
				CreatDG_ALG(ALDG);
				break;
			case 3:
				TopologicalSort(ALDG);
				break;
			default:
				if (n!=4)
					cout<<"错误,又一次输入\n";
		}
	}while(n!=4);
}

/*
*无向网的函数集
*/
//创建无向网的邻接矩阵
bool CreatUDN_M(MGraph &MG)
{
	MG.kind = UDN;
	cout<<"请输入该无向网的顶点个数、弧的条数:"<<endl;
	cin>>MG.vexnum>>MG.arcnum;
	//初始化顶点集合
	cout<<"依次输入顶点序号"<<endl;
	for(int i = 0;i<MG.vexnum;i++)  cin>>MG.vexs[i];
	//初始化邻接矩阵
	for(int i = 0;i<MG.vexnum;i++)
	{
		for(int j = 0;j<MG.vexnum;j++)
		 {
			 MG.arecs[i][j].adj = INFINITY;
		 }
	}
	//构造邻接矩阵
	for(int i = 0;i<MG.arcnum;i++)
	{
		int v1,v2;
		double w;
		cout<<"依次输入弧的两个顶点序号及权值:"<<endl;
		cin>>v1>>v2>>w;
		int *p1 = find(MG.vexs,MG.vexs+MG.vexnum,v1);
		int *p2 = find(MG.vexs,MG.vexs+MG.vexnum,v2);
		if(p1==MG.vexs+MG.vexnum||p2==MG.vexs+MG.vexnum) return false;
		MG.arecs[(p1-MG.vexs)][(p2-MG.vexs)].adj = w;
		//无向图的邻接矩阵是对称矩阵
		MG.arecs[(p2-MG.vexs)][(p1-MG.vexs)].adj = w;
	}
	//输出该邻接矩阵
	cout<<"该邻接矩阵为(-1代表无穷大):"<<endl;
	for(int i = 0;i<MG.vexnum;i++)
	{
		for(int j = 0;j<MG.vexnum;j++)
	  {
		  if(MG.arecs[i][j].adj==INFINITY) cout<<"∞  ";
		  else
		  {
			  cout<<MG.arecs[i][j].adj<<"  ";
		  }
	  }
		cout<<endl;
	}
	return true;
}
//创建无向网的邻接表 
bool CreatUDN_ALG(ALGraph &ALN)
{
	ALN.kind =  UDN;
	cout<<"请输入该无向网的顶点个数、弧的条数:"<<endl;
	cin>>ALN.vexnum>>ALN.arcnum;
	//初始化顶点集合
	cout<<"依次输入顶点序号"<<endl;
	for(int i = 0;i<ALN.vexnum;i++)  cin>>ALN.vexs[i];
	//构造邻接表
	for(int i  = 0;i<ALN.vexnum;i++)
	{
	 //初始化头结点的data信息
		ALN.vertices[i].data = ALN.vexs[i];
		ALN.vertices[i].firstarc = 0;
	 //循环输入该头结点的邻接弧
		cout<<"输入与序号为"<<ALN.vexs[i]<<"节点相邻的节点序号、弧的权值"<<endl;
		int v1;
		double w;
		ArcNode * rp = ALN.vertices[i].firstarc;
		while (cin>>v1)
		{
			cin>>w;
			int *p1 =  find(ALN.vexs,ALN.vexs+ALN.vexnum,v1);
			if(p1==ALN.vexs+ALN.vexnum)return false;
			ArcNode *pA = (ArcNode *)malloc(sizeof(ArcNode));
			if(!pA) return false;
			pA->adj = w;
			pA->adjvex = p1-ALN.vexs;
			pA->nextarc = 0;
			if(0==ALN.vertices[i].firstarc) {ALN.vertices[i].firstarc = pA; rp = pA;}
			else{rp->nextarc = pA; rp = pA;}
		}
		cin.clear();//清空输入流
	}
	//输出邻接表
	for(int i  = 0;i<ALN.vexnum;i++)
	{
		cout<<"'"<<ALN.vexs[i]<<"'";
		for(ArcNode * rp = ALN.vertices[i].firstarc;rp!=0;rp = rp->nextarc)
	  {
		  cout<<"--->"<<(*rp).adjvex;
	  }
		cout<<endl;
	}
	return true;
}
//prim算法求最小生成树
typedef struct 
{
	int adjvex;//顶点序号
	double lowcost;//最短距离
}Closedge[MAX_VERTEX_NUM];
bool MiniSpanTree(MGraph & MN)
{
	Closedge closedge;//记录未选节点到已选节点中最短的距离
	int k = 0;
	//初始化辅组数组
	for(int i = 0;i<MN.vexnum;i++)
	{
		if(i!=k) {closedge[i].lowcost = MN.arecs[i][k].adj;closedge[i].adjvex = MN.vexs[k];}
	}
	closedge[k].lowcost = 0;//标识为已选
	for(int i = 1;i<MN.vexnum;i++)//选择其余的n-1个顶点
	{
	  //求出未选节点中的最短距离
		double low = INFINITY+1;
		
		for(int j = 0;j<MN.vexnum;j++)
		{
			if((closedge[j].lowcost!=0)&&(closedge[j].lowcost<low))
			{
			  k = j;
			  low = closedge[j].lowcost;
			}
		}
		//打印该路线
		cout<<MN.vexs[k]<<"  "<<closedge[k].adjvex<<"  "<<closedge[k].lowcost<<endl;
		//标识为已选
		closedge[k].lowcost = 0;
		//更新最短距离
		for(int j = 0;j<MN.vexnum;j++)
		{
			if(closedge[j].lowcost>MN.arecs[j][k].adj)
			{
				closedge[j].adjvex =MN.vexs[k];
				closedge[j].lowcost = MN.arecs[j][k].adj;
			}
		}
	}
	return true;
}
// kruskal算法求最小生成树
void Kruskal(MGraph & MN)
{
	int i,j,k;
	int n = MN.vexnum;
	AdjMatrix S;//用来表示连通关系
	AdjMatrix Q;//表示节点之间的权值
	//初始化
	for(i=0;i<n;i++)
	for(j=0;j<n;j++){
		if(i==j) S[i][j].adj=1;
		else S[i][j].adj=0;
	Q[i][j].adj = MN.arecs[i][j].adj;
	}
	k=1;
	while(k<n)
	{
	//找到权值最小的边
	double low = INFINITY+1;
	int Begin,End;
	for(i=0;i<n;i++)
	for(j=0;j<n;j++){
		if(Q[i][j].adj<low)
		{
			Begin = i;
			End = j;
			low = Q[i][j].adj;
		}
	}
	Q[Begin][End].adj = INFINITY;//归无穷
	if(0==S[Begin][End].adj)
	{
	cout<<MN.vexs[Begin]<<"---"<<MN.vexs[End]<<"  "<<MN.arecs[Begin][End].adj<<endl;
	k++;
	//更新全局的连通关系
	for(i = 0;i<n;i++)
	{
		  if(S[Begin][i].adj!=0)
		 {
			 S[End][i].adj = S[i][End].adj = 1;
			 //更新相连分支
			 for(int j = 0;j<n;j++)
			 {
			   if(S[End][j].adj!=0)
			   {
			   S[j][i].adj = S[i][j].adj = 1;
			   }
			 }
		 }
	}
	for(i = 0;i<n;i++)
	{
		if(S[End][i].adj!=0)
		{
			S[Begin][i].adj = S[i][Begin].adj = 1;
			//更新相连分支
			 for(int j = 0;j<n;j++)
			 {
			   if(S[Begin][j].adj!=0)
			   {
			   S[j][i].adj = S[i][j].adj = 1;
			   }
			 }
		}
	}

	}//if
	}//while
}
//无向网操作菜单
void IndirectedNet()
{
	MGraph MN;
	ALGraph ALN;
	int n;
	do{
		cout<<"\n";
		cout<<"  ***************无向网的基本操作及应用***************\n";
	    cout<<"  *  1 创建无向网的邻接矩阵                         *\n";
		cout<<"  *  2 创建无向网的邻接表                           *\n";
	    cout<<"  *  3 prim算法求最小生成树                         *\n";
		cout<<"  *  4 kruskal算法求最小生成树                      *\n";
		cout<<"  *  5 退出                                         *\n";
	    cout<<"  ****************************************************\n";
		cin>>n;
		switch(n){
			case 1:
				CreatUDN_M(MN);
				break;
			case 2:
				CreatUDN_ALG(ALN);
				break;
			case 3:
				MiniSpanTree(MN);
				break;
			case 4:
				Kruskal(MN);
				break;
			default:
				if (n!=5)
					cout<<"错误,又一次输入\n";
		}
	}while(n!=5);
	
}

/*
*有向网的函数集
*/
//创建有向网的邻接矩阵
bool CreatDN_M(MGraph &MDN )
{
	MDN.kind = DG;
	cout<<"请输入该有向网的顶点个数、弧的条数:"<<endl;
	cin>>MDN.vexnum>>MDN.arcnum;
	//初始化顶点集合
	cout<<"依次输入顶点序号"<<endl;
	for(int i = 0;i<MDN.vexnum;i++)  cin>>MDN.vexs[i];
	//初始化邻接矩阵
	for(int i = 0;i<MDN.vexnum;i++)
	{
		for(int j = 0;j<MDN.vexnum;j++)
		 {
			 MDN.arecs[i][j].adj = INFINITY;
		 }
	}
	//构造邻接矩阵
	for(int i = 0;i<MDN.arcnum;i++)
	{
		int v1,v2;
		double w;
		cout<<"依次输入弧的弧尾序号、弧头序号、权值:"<<endl;
		cin>>v1>>v2>>w;
		int *p1 = find(MDN.vexs,MDN.vexs+MDN.vexnum,v1);
		int *p2 = find(MDN.vexs,MDN.vexs+MDN.vexnum,v2);
		if(p1==MDN.vexs+MDN.vexnum||p2==MDN.vexs+MDN.vexnum) return false;
		MDN.arecs[(p1-MDN.vexs)][(p2-MDN.vexs)].adj = w;
	}
	//输出该邻接矩阵
	cout<<"该邻接矩阵为:"<<endl;
	for(int i = 0;i<MDN.vexnum;i++)
	{
		for(int j = 0;j<MDN.vexnum;j++)
	  {
		  if(MDN.arecs[i][j].adj==INFINITY) cout<<"∞  ";
		  else
		  {
			  cout<<MDN.arecs[i][j].adj<<"  ";
		  }
	  }
		cout<<endl;
	}
	return true;
}
//创建有向网的邻接表
bool CreatDN_ALG(ALGraph & ALDN)
{
	ALDN.kind =  DG;
	cout<<"请输入该有向网的顶点个数、弧的条数:"<<endl;
	cin>>ALDN.vexnum>>ALDN.arcnum;
	//初始化顶点集合
	cout<<"依次输入顶点序号"<<endl;
	for(int i = 0;i<ALDN.vexnum;i++)  cin>>ALDN.vexs[i];
	//构造邻接表
	for(int i  = 0;i<ALDN.vexnum;i++)
	{
	 //初始化头结点的data信息
		ALDN.vertices[i].data = ALDN.vexs[i];
		ALDN.vertices[i].firstarc = 0;
	 //循环输入该头结点的邻接弧
		cout<<"输入以序号为"<<ALDN.vexs[i]<<"节点为弧尾的弧头节点序号、弧的权值"<<endl;
		int v1;
		double w;
		ArcNode * rp = ALDN.vertices[i].firstarc;
		while (cin>>v1)
		{
			cin>>w;
			int *p1 =  find(ALDN.vexs,ALDN.vexs+ALDN.vexnum,v1);
			if(p1==ALDN.vexs+ALDN.vexnum)return false;
			ArcNode *pA = (ArcNode *)malloc(sizeof(ArcNode));
			if(!pA) return false;
			pA->adj = w;
			pA->adjvex = p1-ALDN.vexs;
			pA->nextarc = 0;
			if(0==ALDN.vertices[i].firstarc) {ALDN.vertices[i].firstarc = pA; rp = pA;}
			else{rp->nextarc = pA; rp = pA;}
		}
		cin.clear();//清空输入流
	}
	//输出邻接表
	for(int i  = 0;i<ALDN.vexnum;i++)
	{
		cout<<"'"<<ALDN.vexs[i]<<"'";
		for(ArcNode * rp = ALDN.vertices[i].firstarc;rp!=0;rp = rp->nextarc)
		{
			  cout<<"--->"<<(*rp).adjvex;
		}
		cout<<endl;
	}
	return true;
}
//关键路径
bool TopologicalOrder(ALGraph & ALDN,stack<int> & T,double ve[] )//T用于保存拓扑排序
{
	//入度数组
	int *indegree = new int[ALDN.vexnum];
	//初始化入度数组
	for(int i = 0;i<ALDN.vexnum;i++)
	{
	  int re= 0;
	  for(int j = 0;j<ALDN.vexnum;j++)
	  {
			if(j!=i)//查找入度
			{
				for(ArcNode * rp = ALDN.vertices[j].firstarc;rp!=0;rp = rp->nextarc)
				{
				   if((*rp).adjvex==i) re++;
				}
			}
	  }
	  indegree[i] = re;
	}
	//保存入度为0的栈
	//初始化事件最早发生数组
	stack<int> Stack;
	for(int i = 0;i<ALDN.vexnum;i++)
	{
		if(0==indegree[i]) Stack.push(i);
		ve[i] = 0;
	}
	
	int count = 0;//记录输出节点的个数
	while (!Stack.empty())
	{
		int v = Stack.top();//出栈
		Stack.pop(); count++;
		T.push(v);
		for(ArcNode * rp = ALDN.vertices[v].firstarc;rp!=0;rp = rp->nextarc)
		{
			--indegree[(*rp).adjvex];
			if(0==indegree[(*rp).adjvex]) Stack.push((*rp).adjvex);
			if(ve[v]+(*rp).adj>ve[(*rp).adjvex]) ve[(*rp).adjvex] = ve[v]+(*rp).adj;
		}
	}
	if(count<ALDN.vexnum)
	{
		return false;
	}
	return true;
}
bool CriticalPath(ALGraph & ALDN )
{
	stack<int>  T;//保存拓扑排序
	double * ve  = new double[ALDN.vexnum];//事件最早发生数组
	if(!TopologicalOrder(ALDN,T,ve)) return false;
	double * vl = new double[ALDN.vexnum];//事件最迟发生数组
	//初始化最迟发生数组
	for(int i = 0;i<ALDN.vexnum;i++)
	{
		vl[i] = ve[T.top()];
	}
	//依照拓扑逆序求各项的最迟发生时间
	while(!T.empty())
	{
		int j = T.top();
		T.pop();
		ArcNode *p = ALDN.vertices[j].firstarc;
		for(;p!=0;p=p->nextarc)
		{
			if((vl[(*p).adjvex]-(*p).adj)<vl[j]) vl[j] = (vl[(*p).adjvex]-(*p).adj);
		}
	}
	//查找关键路径
	for(int i = 0;i<ALDN.vexnum;i++)
	{
		for(ArcNode *p = ALDN.vertices[i].firstarc;p!=0;p=p->nextarc)
		{
			if(ve[i] == (vl[p->adjvex] - p->adj))
			{
				cout<<"*  :"<<ALDN.vexs[i]<<"---"<<ALDN.vexs[p->adjvex]<<"  :"<<ve[i]<<"<--"<<p->adj<<"-->"<<vl[p->adjvex]<<endl;
			}
		}
	}
	return true;
}
//单源顶点最短路径问题
bool ShortestPath(MGraph &MDN,int v0)
{
	AdjMatrix P;//p[v][w]用于记录v0到v点最短路径上的节点 为true则在该最短路径上
	double *D = new double[MDN.vexnum];//记录v0到每一点的最短距离
	bool *fina = new bool[MDN.vexnum];//记录v0是否已经找到到每一点的最短路径
	//初始化參数
	for(int i = 0;i<MDN.vexnum;i++)
	{
		fina[i] = false;
		D[i] = MDN.arecs[v0][i].adj;
		//先把全部路径置空
		for(int j = 0;j<MDN.vexnum;j++) P[i][j].adj = 0;
		if(D[i]<INFINITY)
		{
			P[i][v0].adj = 1;
			P[i][i].adj = 1;
		}
	}
	D[v0] = 0;
	fina[v0] = true;
	//为剩下的n-1个节点查找最短距离
	for(int i = 1;i<MDN.vexnum;i++)
	{
		double min = INFINITY+1;//记录剩下的节点到v0的最短距离
		int mV;//记录剩下的节点到v0的最短距离的节点
		//找出最短距离
		for(int j= 0;j<MDN.vexnum;j++)
		{
			if(!fina[j])
			{
				if(D[j]<min)
				{
					mV= j;
					min = D[j];
				}
			}
		}
		//mV增加找到最短路径集合
		fina[mV] = true;
		//更新剩下的每一个点到v0的最短距离集合 及 最短路径集合
		for(int j= 0;j<MDN.vexnum;j++)
		{
			if(!fina[j]&&(min+MDN.arecs[mV][j].adj<D[j]))
			{
				D[j] = min+MDN.arecs[mV][j].adj;
				//更新最短路径集合
				for(int a = 0;a<MDN.vexnum;a++)
				{
					P[j][a].adj = P[mV][a].adj; 
				}
				P[j][j].adj = 1;
			}

		}
	}
	//输出測试数据
	for(int j= 0;j<MDN.vexnum;j++)
	{
		//先推断是否存在最短路径
		if(D[j]==INFINITY)
		{
			cout<<MDN.vexs[j]<<"  无"<<endl;
		}
		else
		{
			//先输出最短路径
			cout<<MDN.vexs[j]<<"     ";
			for(int i = 0;i<MDN.vexnum;i++)
			{
				if(1==P[j][i].adj)
				{
					cout<<MDN.vexs[i]<<"   ";
				}
			}
			cout<<"最短距离: "<<D[j]<<endl;
		}
	
	}

	return true;
}
//有向网操作菜单
void DirectedNet()
{
	MGraph MDN;
	ALGraph ALDN;
	int n;
	do{
		cout<<"\n";
		cout<<"  ***************有向网的基本操作及应用***************\n";
	    cout<<"  *  1 创建有向网的邻接矩阵                         *\n";
		cout<<"  *  2 创建有向网的邻接表                           *\n";
	    cout<<"  *  3 关键路径                                     *\n";
		cout<<"  *  4 单源顶点最短路径问题                         *\n";
		cout<<"  *  5 退出                                         *\n";
	    cout<<"  ****************************************************\n";
		cin>>n;
		switch(n){
			case 1:
				CreatDN_M(MDN);
				break;
			case 2:
				CreatDN_ALG(ALDN);
				break;
			case 3:
				CriticalPath(ALDN);
				break;
			case 4:
				ShortestPath(MDN,0);
				break;
			default:
				if (n!=5)
					cout<<"错误,又一次输入\n";
		}
	}while(n!=5);
}

void main()
{
	int n;
	do{
		ShowMainMenu();
		cin>>n;
		switch(n){
			case 1:
				UndirectedGraph();
				break;
			case 2:
                DirectedGraph();
				break;
			case 3:
				IndirectedNet();
				break;
			case 4:
				DirectedNet();
				break;
			default:
				if (n!=5)
					cout<<"错误,又一次输入\n";
		}
	}while(n!=5);
}


posted @ 2016-01-02 15:24  mengfanrong  阅读(963)  评论(2编辑  收藏  举报